<?php

/**
 *      @file image.class.php
 *      
 *        @version 0.0.5
 *        
 *      @copyright 2012 Nguyen Van Anh <anhsk.ohbo@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */


class image {

    // Error display
    const ERR_NO_FILE_SELECT = "Sorry! No image file selected!";
    const ERR_UNKNOWN_IMAGE  = "The file is not a known image format!";
    const ERR_READ_IMAGE = "The file is not readable!";
    const ERR_INFO_IMAGE = "File is not supplied or is not a file!";
    const ERR_TYPE_IMAGE = "Image type not supported!";
    const ERR_MIME_IMAGE = "Image mime type not supported!";
    const ERR_NOT_CREATR = "Couldn't create image!";
    const ERR_UNKNOWN    = "Unkown Error!";
    
    /**
     * $image_source
     * Source image - src or url
     */
    protected $image_source;

    /**
     * $is_url
     * Check if source is url
     */
    protected $is_url = false;

    /**
     * $create_image
     * Check if image's working...
     */
    protected $create_image = false;
    
    /**
     * $is_destroy
     * Check is destroy
     */
    protected $is_destroy = false;

    /**
     * $image_info
     * Array info image
     */
    public $image_info = array();
    
    /**
     * $create_image_info
     * Array info Image is created
     */
    public $create_image_info = array();

    /**
     * $error
     * Error display if exists
     */
    public $error = null;


    /*********************************
     *                                 *
     *        Public function              *
     *                                  *
     *********************************/ 
     
    /**
     * __construct() - Construct function
     * @param $image_source (string) - Source to image or link to image
     */
    public function __construct( $image_source = '', $tmp_dir = '') {

        if( empty( $image_source)) {
            $this->error = $this::ERR_NO_FILE_SELECT;
        }
        // Check if image...
        $this->image_source = $image_source;
        if ( preg_match( "/(http|ftp|https):\/\//i", $image_source )){
            $this->is_url = true;
            $tmpfname = tempnam( $tmp_dir, "tmp_" );
            $input = @fopen( $image_source, "rb" );
            if( $input) {
                $output = fopen( $tmpfname, "wb" );
                while ( $data = fread( $input, 1024 ) ) {
                    fwrite( $output, $data );
                }
                fclose( $output);
                fclose( $input);
            }
            $this->image_source = $tmpfname;
        }

        $this->image_info = $this->_imageinfo( $this->image_source);
        $this->error = $this->_checkimage();

        if( empty( $this->error)) {
            $this->_createimage();
        }
    }

    /**
     * resize() - Resize image
     * @param $width (int) - Width for new image 
     * @param $height(int) - height for new image
     */
    public function resize( $width, $height) {
        if ( empty( $this->error ) ) {
            $this->_checkdestroy();
            // Check value width & height
            $width = intval( $width );
            $height = intval( $height);
            if( $width < 0 || $width >= $this->create_image_info['width']) $width = $this->create_image_info['width'];
            if( $height < 0 || $height >= $this->create_image_info['height']) $height = $this->create_image_info['height'];
            if( ( $width != 0 || $height != 0) && ( $width != $this->create_image_info['width'] || $height != $this->create_image_info['height']) ) {
                $this->_workingimage(0,0,0,0, $width, $height, $this->create_image_info['width'], $this->create_image_info['height']);
            }
        }
    }
    
    /**
     * resizeToWidth() - Resize image to width. Height of image will  auto resize
     * @param $width (int) - Width for new image
     */
    public function resizeToWidth( $width) {
        if ( empty( $this->error ) ) {
            $ratio = $width / $this->create_image_info['width'];
            $height = ($this->create_image_info['height'] * $ratio);
            $this->resize($width, $height);
        }
    }

    /**
     * resizeToHeight() - Resize image to height. Width of image will  auto resize
     * @param $height (int) - Height for image
     */
    public function resizeToHeight($height) {
        if ( empty( $this->error ) ) {
            $ratio = $height / $this->create_image_info['height'];
            $width = ($this->create_image_info['width'] * $ratio);
            $this->resize($width, $height);
        }
    }
    
    /**
     * resizeToScale() - Resize image to scale
     * @param $scale (int) - From 1 to 100
     */
    public function resizeToScale($scale) {
        if ( empty( $this->error ) ) {
            $width = ($this->create_image_info['width'] * $scale/100);
            $height = ($this->create_image_info['height'] * $scale/100);
            $this->resize($width, $height);
        }
    }

    /**
     * crop() - Crop simple image
     * @param $dst_x (int), x-coordinate of destination point.
     * @param $dst_y (int), y-coordinate of destination point.
     * @param $src_x (int), x-coordinate of source point.
     * @param $src_y (int), y-coordinate of source point.
     * @param $newwidth (int), Destination width.
     * @param $newheight (int),Destination height.
     */
    public function crop( $dst_x, $dst_y, $src_x , $src_y, $newwidth, $newheight, $w, $h) {
        if( empty( $this->error)) {
            $this->_checkdestroy();

            $dst_x = intval( $dst_x );
            $dst_y = intval( $dst_y );
            $src_x = intval( $src_x );
            $src_y = intval( $src_y );
            $newwidth = intval( $newwidth );
            $newheight = intval( $newheight );

            if ( $dst_x < 0 || $dst_x >= $this->create_image_info['width'] ) $dst_x = 0;
            if ( $dst_y < 0 || $dst_y >= $this->create_image_info['height'] ) $dst_y = 0;
            if ( $src_x < 0 || $src_x >= $this->create_image_info['width'] ) $src_x = 0;
            if ( $src_y < 0 || $src_y >= $this->create_image_info['height'] ) $src_y = 0;
            if( $newwidth <= 0 || $newwidth > $this->create_image_info['width'] ) $newwidth = $this->create_image_info['width'];
            if( $newwidth <= 0 || $newwidth > $this->create_image_info['height'] ) $newwidth = $this->create_image_info['height'];
            if( ($newwidth < $this->create_image_info['width']) || ( $newwidth < $this->create_image_info['height'])) {
                $this->_workingimage($dst_x, $dst_y, $src_x , $src_y, $newwidth, $newheight, $w, $h);
            }
        }
    }
    
    /**
     * cropFromLeft()
     * @param $leftX (int)
     * @param $leftY (int)
     * @param $width (int) - Width for new image
     * @param $height (int) - Height for new image
     */
    public function cropFromLeft( $leftX, $leftY, $width, $height) {
        if( empty( $this->error)) {
            $this->crop(0, 0, $leftX, $leftY, $width, $height, $width, $height);
        }
    }
    
    /**
     * cropFromCenter() - Crop image auto
     * @param $width (int)
     * @param $hegiht (int)
     */
    public function cropFromCenter( $width, $height) {
        if( empty( $this->error)) {
            if( $width <= 0 || $width > $this->create_image_info['width'] ) $width = $this->create_image_info['width'];
            if( $height <= 0 || $height > $this->create_image_info['height'] ) $height = $this->create_image_info['height'];
            $leftX = ( $this->create_image_info['width'] - $width ) / 2;
            $leftY = ( $this->create_image_info['height'] - $height ) / 2;
            $this->crop(0, 0, $leftX, $leftY, $width, $height, $width, $height);
        }
    }
    
    /**
     * show()
     * @param $quality (int) - Quality for image show, default = 100 
     */
    public function show( $quality = 100 ) {
        if ( empty( $this->error )){
            $this->_checkdestroy();
            header( "Content-Type: " . $this->create_image_info['mime'] );
            $this->_createtype(null, $quality);
            $this->destroy();
        }
    }

    /**
     * save() - Save to Image
     * @param $parh (string)- Dir save new image
     * @param $newname (string) - New name for image. Default will auto rename
     * @param $quality (int) - Quality for image. From 1 to 100
     * @param $newdir (string) - if is true it's will create new dir if dir not exists
     */
    public function save( $path, $newname = '', $quality = 100, $newdir = false ) {
        if ( empty( $this->error )) {
            $this->_checkdestroy();
            if( $newdir && !file_exists( $path)) {
                mkdir( $path, 0700);
            }
            if ( is_dir( $path ) and is_writeable( $path ) ) {

                if ( empty( $newname ) ) {
                    $newname ="";
                    $basename = ( $this->create_image_info['name']);
                    if ( !empty( $basename ) ) {
                        $newname .= '_' . $basename;
                    }
                }

                $newname = preg_replace( '/^\W+|\W+$/', '', $newname );
                $newname = preg_replace( '/\s+/', '_', $newname );
                $newname = strtolower( preg_replace( '/\W-/', '', $newname ) );
                $newname = preg_replace( "/." . $this->create_image_info['ext'] . "$/", '', $newname );
                if ( ! preg_match( "/\/$/", $path ) ) $path = $path . "/";

                $newname = $path . $newname . '.' . $this->create_image_info['ext'];
                
                $this->_createtype($newname, $quality);
                $this->create_image_info['src'] = $newname;
                $this->create_image_info['name'] = $this->_getname( $this->create_image_info['src']);

                $this->destroy();
            }
            else $this->error = $this::ERR_NOT_CREATR;
        }
    }
    

    /*********************************
     *                                 *
     *        Protected function         *
     *                                  *
     *********************************/  
     
     /**
      * _imageinfo()
      * @param $image_source - Image file path
      * @return array() - Info for image: src, name, width, height, mime, ext, type, bits, channels.
      */
    protected function _imageinfo( $image_source) {
        $imageinfo = array();
        $flag_image = array(
            1  => array( 'type' => IMAGETYPE_GIF,  'ext' => 'gif' ),
            2  => array( 'type' => IMAGETYPE_JPEG, 'ext' => 'jpg' ),
            3  => array( 'type' => IMAGETYPE_PNG,  'ext' => 'png' ),
            4  => array( 'type' => IMAGETYPE_SWF,  'ext' => 'swf' ),
            5  => array( 'type' => IMAGETYPE_PSD,  'ext' => 'psd' ),
            6  => array( 'type' => IMAGETYPE_BMP,  'ext' => 'bmp' ),
            7  => array( 'type' => IMAGETYPE_TIFF_II, 'ext' => 'tiff' ),
            8  => array( 'type' => IMAGETYPE_TIFF_MM, 'ext' => 'tiff' ),
            9  => array( 'type' => IMAGETYPE_JPC, 'ext' => 'jpc' ),
            10 => array( 'type' => IMAGETYPE_JP2, 'ext' => 'jp2' ),
            11 => array( 'type' => IMAGETYPE_JPX, 'ext' => 'jpf' ),
            12 => array( 'type' => IMAGETYPE_JB2, 'ext' => 'jb2' ),
            13 => array( 'type' => IMAGETYPE_SWC, 'ext' => 'swc' ),
            14 => array( 'type' => IMAGETYPE_IFF, 'ext' => 'aiff' ),
            15 => array( 'type' => IMAGETYPE_WBMP,'ext' => 'wbmp' ),
            16 => array( 'type' => IMAGETYPE_XBM, 'ext' => 'xbm' ),
        );
        $basename = $this->_getname( $this->image_source);
        $image_info_arr = @getimagesize( $image_source );
        if ( $image_info_arr ) {
            $imageinfo = array(
                'src'      => $image_source,
                'name'     => $basename,
                'width'    => $image_info_arr[0],
                'height'   => $image_info_arr[1],
                'mime'     => $image_info_arr['mime'],
                'ext'      => $flag_image[$image_info_arr[2]]['ext'],
                'type'     => $flag_image[$image_info_arr[2]]['type'],
                // 'bits'     => $image_info_arr['bits'],
                // 'channels' => isset( $image_info_arr['channels'] ) ? intval( $image_info_arr['channels'] ) : 0,
            );
        }
        return $imageinfo;
    }
    
    /**
     * _checkimage()
     * @return string error
     */
    protected function _checkimage() {
        if( $this->image_info == array() ) {
            return $this::ERR_UNKNOWN_IMAGE;
        }
        elseif( !is_readable( $this->image_source ) ) {
            return $this::ERR_READ_IMAGE;    
        }
        elseif( $this->image_info['src'] == '' || $this->image_info['width'] == 0 || $this->image_info['height'] == 0 || $this->image_info['mime'] == '' ) {
                return $this::ERR_INFO_IMAGE;
        }
        elseif( !in_array( $this->image_info['type'], array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG ) ) ) {
            return $this::ERR_TYPE_IMAGE;
        }
        elseif( !preg_match( "#image\/[x\-]*(jpg|jpeg|gif|png)#is", $this->image_info['mime'] ) ) {
            return $this::ERR_MIME_IMAGE;
        }
        return null;
    }
    
    /**
     * _getname() - get name
     * @param $image_source (string) - String image source
     */
    protected function _getname( $image_source) {
        $basename = '';
        if ( defined( 'PATHINFO_FILENAME' ) ) $basename = @pathinfo( $image_source, PATHINFO_FILENAME );
        else $basename = strstr( $image_source, '.' ) ? substr( $image_source, 0, strrpos( $image_source, '.' ) ) : "";
        return $basename;
    }
    
    /**
     * _createimage()
     */
    protected function _createimage() {
        switch ( $this->image_info['type'] ) {
            case IMAGETYPE_GIF:
                $this->create_image = @imagecreatefromgif( $this->image_source);
                break;
            case IMAGETYPE_JPEG:
                $this->create_image = @imagecreatefromjpeg( $this->image_source);
                break;
            case IMAGETYPE_PNG:
                $this->create_image = @imagecreatefrompng( $this->image_source);
                break;
        }
        if ( $this->create_image ) {
            $this->create_image_info = $this->image_info;
            $this->is_destroy = false;
        }
        else $this->error = $this::ERR_NOT_CREATR;
    }

    /**
     * _createtype()
     */
    protected function _createtype( $newname = null, $quality = 100) {
        if( empty( $this->error)) {
            switch ( $this->create_image_info['type'] ) {
                case IMAGETYPE_GIF:
                    @imagegif( $this->create_image, $newname);
                    break;
                case IMAGETYPE_JPEG:
                    @imagejpeg( $this->create_image, $newname, $quality);
                    break;
                case IMAGETYPE_PNG:
                    @imagepng( $this->create_image, $newname);
                    break;
            }
        }
    }
    
    /**
     * _workingimage() - Using imagecopyresampled function
     */
    protected function _workingimage($dst_x, $dst_y, $src_x , $src_y, $newwidth, $newheight, $source_width, $source_height) {

        if( function_exists( "imagecreatetruecolor" ) ) {
            $workingImage = imagecreatetruecolor( $newwidth, $newheight);
        }
        else {
            $workingImage = imagecreate( $newwidth, $newheight );
        }
        if ( $workingImage != false ) {
            $transparent_index = imagecolortransparent( $this->create_image );
            if ( $transparent_index >= 0 ) {
                $color = imagecolorsforindex( $this->create_image, $transparent_index );
                $transparent_index = imagecolorallocate( $workingImage, $color['red'], $color['green'], $color['blue'] );
                if ( $transparent_index !== false && imagefill( $workingImage, 0, 0, $transparent_index ) ) {
                    imagecolortransparent( $workingImage, $transparent_index );
                }
            }
            if ( $this->create_image_info['type'] == IMAGETYPE_PNG ) {
                if ( imagealphablending( $workingImage, false ) ) {
                    $transparency = imagecolorallocatealpha( $workingImage, 0, 0, 0, 127 );
                    if ( $transparency !== false && imagefill( $workingImage, 0, 0, $transparency ) ) {
                        imagesavealpha( $workingImage, true );
                    }
                }
            }
            if ( imagecopyresampled( $workingImage, $this->create_image, $dst_x, $dst_y, $src_x , $src_y, $newwidth, $newheight, $source_width, $source_height) ) {
                $this->create_image = $workingImage;
                $this->create_image_info['width'] = $newwidth;
                $this->create_image_info['height'] = $newheight;
            }
            else $this->error = $this::ERR_NOT_CREATR;
        }
    }
    
    /**
     * _checkdestroy()
     */
    protected function _checkdestroy() {
        if ( $this->is_destroy ){
            $this->_createimage();
        }
    }
    
    /**
     * @name destroy();
     * @return destroy session  working of image
     */
    protected function destroy() {
        if ( is_resource( $this->create_image )) {
            @imagedestroy( $this->create_image );
        }
        if ( $this->is_url ) {
            @unlink( $this->image_info['src'] );
            $this->is_url = false;
        }
        $this->is_destroy = true;
    }
}

?>